/*******************************************************************************
 * Copyright (c) 2013 QPark Consulting  S.a r.l.
 * 
 * This program and the accompanying materials are made available under the 
 * terms of the Eclipse Public License v1.0. 
 * The Eclipse Public License is available at 
 * http://www.eclipse.org/legal/epl-v10.html.
 * 
 * Contributors:
 *     Bernhard Hausen - Initial API and implementation
 *
 ******************************************************************************/
package com.qpark.maven.plugin.router;

import java.io.File;

import org.apache.maven.plugin.AbstractMojo;
import org.apache.maven.plugin.MojoExecutionException;
import org.apache.maven.plugin.MojoFailureException;
import org.apache.maven.plugins.annotations.LifecyclePhase;
import org.apache.maven.plugins.annotations.Mojo;
import org.apache.maven.plugins.annotations.Parameter;

import com.qpark.maven.Util;
import com.qpark.maven.xmlbeans.ComplexType;
import com.qpark.maven.xmlbeans.ElementType;
import com.qpark.maven.xmlbeans.XsdsUtil;

/**
 * Create standard router definitions as property files for all not existing definitions. These
 * standard router properties are using the {@link RouterProperitesMojo#ROUTER_TYPE_FORWARD} to the
 * generated mock operation providers.
 * @author bhausen
 */
@Mojo(name = "generate-router-properties", defaultPhase = LifecyclePhase.PROCESS_CLASSES)
public class RouterProperitesMojo extends AbstractMojo {
	public static final String ROUTER_CHANNEL_WS_REQUEST = "router.channel.ws.request";
	public static final String ROUTER_CHANNEL_WS_RESPONSE = "router.channel.ws.response";
	public static final String ROUTER_OPERATION_NAME = "router.operation.name";
	public static final String ROUTER_OPERATION_PROVIDER_BEAN_NAME = "router.operation.provider.bean.name";
	public static final String ROUTER_OPERATION_PROVIDER_CLASS_NAME_MOCK = "router.operation.provider.class.name.mock";
	public static final String ROUTER_RESPONSE_AGGREGATOR_BEAN_NAME = "router.response.aggregator.bean.name";
	public static final String ROUTER_CHANNEL_OUTGOING = "router.channel.outging.name";
	public static final String ROUTER_CHANNEL_INCOMING = "router.channel.incoming.name";
	public static final String ROUTER_SERVICE_ID = "router.service.id";
	public static final String ROUTER_TYPE = "router.type";
	public static final String ROUTER_TYPE_FORWARD = "forward";
	public static final String ROUTER_TYPE_CHANNEL_ROUTER = "channel-router";
	public static final String ROUTER_TYPE_RECIPIENT_LIST_ROUTER = "recipient-list-router";
	public static final String ROUTER_TYPE_PAYLOAD_TYPE_ROUTER = "payload-type-router";
	public static final String ROUTER_TYPE_HEADER_VALUE_ROUTER = "header-value-router";
	/** The base directory where to start the scan of xsd files. */
	@Parameter(property = "baseDirectory", defaultValue = "${project.build.directory}/model")
	protected File baseDirectory;
	/** The base package name where to place the object factories. */
	@Parameter(property = "basePackageName", defaultValue = "")
	protected String basePackageName;

	/**
	 * The package name of the delta should contain this. Default is <code>delta</code>.
	 */
	@Parameter(property = "deltaPackageNameSuffix", defaultValue = "delta")
	private String deltaPackageNameSuffix;

	/**
	 * The package name of the messages should end with this. Default is <code>msg</code>.
	 */
	@Parameter(property = "messagePackageNameSuffix", defaultValue = "msg")
	protected String messagePackageNameSuffix;
	/** The base directory where to start the scan of xsd files. */
	@Parameter(property = "outputDirectory", defaultValue = "${project.build.directory}/classes/router/definitions")
	protected File outputDirectory;
	/** <code>true</code>, if common service/config... should be generated too. */
	@Parameter(property = "serviceCreationWithCommon", defaultValue = "true")
	private boolean serviceCreationWithCommon;
	/** The name of the service id to generate. If empty use all. */
	@Parameter(property = "serviceId", defaultValue = "")
	private String serviceId;
	/** The name of the service id of common services. */
	@Parameter(property = "serviceIdCommonServices", defaultValue = "common")
	private String serviceIdCommonServices;
	/**
	 * The service request name need to end with this suffix (Default <code>Request</code>).
	 */
	@Parameter(property = "serviceRequestSuffix", defaultValue = "Request")
	private String serviceRequestSuffix;
	/**
	 * The service response name need to end with this suffix (Default <code>Response</code>).
	 */
	@Parameter(property = "serviceResponseSuffix", defaultValue = "Response")
	private String serviceResponseSuffix;

	/**
	 * @see org.apache.maven.plugin.Mojo#execute()
	 */
	@Override
	public void execute() throws MojoExecutionException, MojoFailureException {
		this.getLog().debug("+execute");
		this.getLog().debug("get xsds");
		XsdsUtil xsds = new XsdsUtil(this.baseDirectory, this.basePackageName,
				this.messagePackageNameSuffix, this.deltaPackageNameSuffix,
				this.serviceRequestSuffix, this.serviceResponseSuffix);
		StringBuffer sb = new StringBuffer(1024);
		String fileName;
		File f;
		for (ElementType element : xsds.getElementTypes()) {
			if (element.isRequest()
					&& Util.isValidServiceId(element.getServiceId(),
							this.serviceId, this.serviceIdCommonServices,
							this.serviceCreationWithCommon)) {
				fileName = new StringBuffer(32).append(element.getServiceId())
						.append(element.getOperationName())
						.append("RouterConfig.properties").toString();
				f = Util.getFile(this.outputDirectory, fileName);
				ElementType elementResponse = XsdsUtil.findResponse(element,
						xsds.getElementTypes(), xsds);
				if (elementResponse != null && !f.exists()) {
					ComplexType ctResponse = new ComplexType(elementResponse
							.getElement().getType(), xsds);
					if (ctResponse != null && !ctResponse.isSimpleType()
							&& !ctResponse.isPrimitiveType()) {
						sb.setLength(0);

						sb.append("# Router properties of ");
						sb.append(element.getServiceId());
						sb.append(".");
						sb.append(element.getOperationName());
						sb.append("\n");
						sb.append("# ");
						sb.append(Util.getGeneratedAt());
						sb.append("\n");
						sb.append(ROUTER_SERVICE_ID);
						sb.append("=");
						sb.append(element.getServiceId());
						sb.append("\n");
						sb.append(ROUTER_OPERATION_NAME);
						sb.append("=");
						sb.append(element.getOperationName());
						sb.append("\n");
						sb.append(ROUTER_CHANNEL_WS_REQUEST);
						sb.append("=");
						sb.append(element.getChannelNameWsRequest());
						sb.append("\n");
						sb.append(ROUTER_CHANNEL_WS_RESPONSE);
						sb.append("=");
						sb.append(element.getChannelNameWsResponse());
						sb.append("\n");
						sb.append(ROUTER_TYPE);
						sb.append("=");
						sb.append(ROUTER_TYPE_FORWARD);
						sb.append("\n");
						sb.append(ROUTER_OPERATION_PROVIDER_BEAN_NAME);
						sb.append(".0=");
						sb.append(element.getBeanIdMockOperationProvider());
						sb.append("\n");
						sb.append("# Only when using the a mock ");
						sb.append(ROUTER_OPERATION_PROVIDER_CLASS_NAME_MOCK);
						sb.append(" needs to be set.\n");
						sb.append(ROUTER_OPERATION_PROVIDER_CLASS_NAME_MOCK);
						sb.append("=");
						sb.append(element
								.getClassNameFullQualifiedMockOperationProvider());
						sb.append("\n");
						sb.append("#\n");
						sb.append("# Alternativly you can route to directly to a channel.\n");
						sb.append("# In this case you need to define an outgoing and incoming channel.\n");
						sb.append("#");
						sb.append(ROUTER_TYPE);
						sb.append("=");
						sb.append(ROUTER_TYPE_CHANNEL_ROUTER);
						sb.append("\n");
						sb.append("#");
						sb.append(ROUTER_CHANNEL_OUTGOING);
						sb.append("=");
						sb.append("\n");
						sb.append("#");
						sb.append(ROUTER_CHANNEL_INCOMING);
						sb.append("=");
						sb.append("\n");
						sb.append("#\n");
						sb.append("# Or you can route to a list of beans.\n");
						sb.append("#");
						sb.append(ROUTER_TYPE);
						sb.append("=");
						sb.append(ROUTER_TYPE_RECIPIENT_LIST_ROUTER);
						sb.append("\n");
						sb.append("#");
						sb.append(ROUTER_TYPE);
						sb.append("=");
						sb.append(ROUTER_TYPE_PAYLOAD_TYPE_ROUTER);
						sb.append("\n");
						sb.append("#");
						sb.append(ROUTER_TYPE);
						sb.append("=");
						sb.append(ROUTER_TYPE_HEADER_VALUE_ROUTER);
						sb.append("\n");
						sb.append("# In the case of multiple recipients of the request\n");
						sb.append("# you need to define an aggregator that combines the responses\n");
						sb.append("# to route the collected responses to the web service caller.\n");
						sb.append("#");
						sb.append(ROUTER_RESPONSE_AGGREGATOR_BEAN_NAME);
						sb.append("=\n");

						this.getLog().info(
								new StringBuffer().append("Write ").append(
										f.getAbsolutePath()));
						try {
							Util.writeToFile(f, sb.toString());
						} catch (Exception e) {
							this.getLog().error(e.getMessage());
							e.printStackTrace();
						}

					}
				}
			}
		}
		this.getLog().debug("-execute");
	}
}
